/*
 * Copyright 2009 Jeremy Thomerson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function JValidationEngine() {
	this.formsToValidate = new Array();
}

JValidationEngine.ERROR_ONLY		= 'e';
JValidationEngine.SUCCESS_ONLY		= 's';
JValidationEngine.ERROR_OR_SUCCSS	= 'b';


JValidationEngine.prototype.triggerOnErrorForMode = function(mode) {
	return mode == undefined || mode == JValidationEngine.ERROR_ONLY || mode == JValidationEngine.ERROR_OR_SUCCESS;
};

JValidationEngine.prototype.triggerOnSuccessForMode = function(mode) {
	return mode == undefined || mode == JValidationEngine.SUCCESS_ONLY || mode == JValidationEngine.ERROR_OR_SUCCESS;
};

JValidationEngine.prototype.addFormLevelHandler = function(handler, form, mode) {
	handler.setForm(form);
	var jform = $(form);
	if (this.triggerOnErrorForMode(mode)) {
		jform.bind('formValidationFailed', function(event) {
			handler.execute(false);
		});
	}
	if (this.triggerOnSuccessForMode(mode)) {
		jform.bind('formValidationSuccessful', function(event) {
			handler.execute(true);
		});
	}
};

JValidationEngine.prototype.addEveryElementHandler = function(handler, form, mode) {
	handler.setForm(form);
	var jform = $(form);
	if (this.triggerOnErrorForMode(mode)) {
		jform.bind('elemValidationFailed', function(event) {
			var jelem = $(event.target);
			handler.execute(jelem, false);
		});
	}
	if (this.triggerOnSuccessForMode(mode)) {
		jform.bind('elemValidationSuccessful', function(event) {
			var jelem = $(event.target);
			handler.execute(jelem, true);
		});
	}
};

JValidationEngine.prototype.addElementLevelHandler = function(handler, element, mode) {
	var jelem = $(element);
	if (this.triggerOnErrorForMode(mode)) {
		jelem.bind('elemValidationFailed', function() {
			handler.execute(jelem, false);
		});
	}
	if (this.triggerOnSuccessForMode(mode)) {
		jelem.bind('elemValidationSuccessful', function() {
			handler.execute(jelem, true);
		});
	}
};

JValidationEngine.prototype.addValidator = function(validator, failureHandler, successHandler) {
	this.addValidatorOnEvent(null, element, validator, failureHandler, successHandler);
};

JValidationEngine.prototype.addValidatorOnEvent = function(event, validator, failureHandler, successHandler) {
	if (!validator) {
		console.error('you must provide a validator to addValidatorOnEvent');
		return;
	}
	var element = validator.field;
	var form = element.form;
	var jelem = $(element);
	var jform = $(form);

	// make sure the form is in our array of forms to validate
	if (jQuery.inArray(form, this.formsToValidate) < 0) {
		this.formsToValidate.push(form);
		jform.data('jValErrorMessages', new Array());
		// register an event that triggers validation on the form
		jform.bind('jValidate', function() {
			jVal.validateForm(this);
		});
	}
	this.defineArray(jform, 'jElements');
	if (jQuery.inArray(element, jform.data('jElements')) < 0) {
		jform.data('jElements').push(element);
	}
	
	this.prepareElementForValidatorRegistration(jelem);
	jelem.data('jValidators').push(validator);
	if (failureHandler) {
		jelem.data('jFailureHandlers').push(failureHandler);
	}
	if (successHandler) {
		jelem.data('jSuccessHandlers').push(successHandler);
	}
	jelem.bind(event, function() {
		validator.validate(this);
	});
	if (!jelem.data('jValidateEventRegistered')) {
		jelem.bind('jValidate', function() {
			jVal.validateElement(this);
		});
		jelem.bind('elemValidationSuccessful', function() {
			
		});
		jelem.bind('elemValidationFailed', function() {

		});
		jelem.data('jValidateEventRegistered', true);
	}
}

JValidationEngine.prototype.prepareElementForValidatorRegistration = function(elem) {
	this.defineArray(elem, 'jValidators');
	this.defineArray(elem, 'jFailureHandlers');
	this.defineArray(elem, 'jSuccessHandlers');
}

JValidationEngine.prototype.defineArray = function(elem, arrayName) {
	if (!elem.data(arrayName)) {
		elem.data(arrayName, new Array());
	}
}

JValidationEngine.prototype.addErrorMessagesToElement = function(element, fieldFriendlyName, errorMessages) {
	console.debug('addErrorMessagesToElement(' + element + ', ' + fieldFriendlyName + ', ' + errorMessages + ')');
	var jelem = $(element);
	var jform = $(element.form);
	
	jelem.data('jValFriendlyName', fieldFriendlyName);
	var existing = jelem.data('jValErrorMessages');
	var all = existing ? jQuery.merge(existing, errorMessages) : errorMessages;
	jelem.data('jValErrorMessages', all);
};


JValidationEngine.prototype.validateForm = function(form) {
	console.info('validating form: ' + form);
	var jform = $(form);
	jform.data('jValIsProcessingForm', true);
	var succeeded = true;
	if (jform.data('jElements')) {
		$(jform.data('jElements')).each(function() {
			var jelem = $(this);
			jelem.data('jValErrorMessages', new Array());
			var elemSucceeded = jVal.validateElement(this);
			if (!elemSucceeded) {
				succeeded = false;
			}
		});;
	}
	jform.data('jValIsProcessingForm', false);
	if (succeeded) {
		console.debug('triggering form formValidationSuccessful');
		jform.trigger('formValidationSuccessful');
	} else {
		console.debug('triggering form formValidationFailed');
		jform.trigger('formValidationFailed');
	}
	return succeeded;
}

JValidationEngine.prototype.validateElement = function(element) {
	console.info('validating element: ' + element);
	var jelem = $(element);
	var succeeded = true;
	if (jelem.data('jValidators')) {
		$(jelem.data('jValidators')).each(function() {
			var valSucceeded = this.validate();
			if (!valSucceeded) {
				succeeded = false;
			}
		});;
	}
	return succeeded;
}

jVal = new JValidationEngine();
